home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2000 #1 / Amiga Plus CD - 2000 - No. 1.iso / Tools / Dev / mamesrc / src / amiga / video.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-12-03  |  51.1 KB  |  1,906 lines

  1. /**************************************************************************
  2.  *
  3.  * Copyright (C) 1999 Mats Eirik Hansen (mats.hansen@triumph.no)
  4.  *
  5.  * $Id: video.c,v 1.2 1999/04/28 18:55:01 meh Exp $
  6.  *
  7.  * $Log: video.c,v $
  8.  * Revision 1.2  1999/04/28 18:55:01  meh
  9.  * *** empty log message ***
  10.  *
  11.  * Revision 1.1  1999/04/20 18:52:45  meh
  12.  * Initial revision
  13.  *
  14.  *************************************************************************/
  15.  
  16. #include <stdio.h>
  17.  
  18. #include <clib/alib_protos.h>
  19.  
  20. #include <exec/types.h>
  21. #include <exec/memory.h>
  22. #include <graphics/gfxbase.h>
  23. #include <graphics/rastport.h>
  24. #include <intuition/intuition.h>
  25. #include <intuition/screens.h>
  26. #include <libraries/iffparse.h>
  27. #include <libraries/gadtools.h>
  28. #include <libraries/asl.h>
  29. #include <cybergraphx/cybergraphics.h>
  30. #include <cgxhooks.h>
  31.  
  32. #include <inline/exec.h>
  33. #include <inline/dos.h>
  34. #include <inline/graphics.h>
  35. #include <inline/cybergraphics.h>
  36. #include <inline/intuition.h>
  37. #include <inline/gadtools.h>
  38. #include <inline/asl.h>
  39. #include <inline/utility.h>
  40.  
  41. #define TIMER_BASE_NAME video->TimerBase
  42. #include <inline/timer.h>
  43.  
  44. #ifdef POWERUP
  45. #include <exec/execbase.h>
  46. #include <powerup/ppclib/memory.h>
  47. #include <inline/ppc.h>
  48. #endif
  49.  
  50. #include <macros.h>
  51. #include "video.h"
  52.  
  53. #define ABS(a) ((a>=0)?(a):-(a))
  54.  
  55. struct BackFillMsg
  56. {
  57.   struct Layer    *Layer;
  58.   struct Rectangle  Bounds;
  59.   LONG        OffsetX;
  60.   LONG        OffsetY;
  61. };
  62.  
  63. struct BMHD
  64. {
  65.   UWORD Width;
  66.   UWORD Height;
  67.   WORD  Left;
  68.   WORD  Top;
  69.   UBYTE Planes;
  70.   UBYTE Masking;
  71.   UBYTE Compression;
  72.   UBYTE pad;
  73.   UWORD TransparentColor;
  74.   UBYTE XAspect;
  75.   UBYTE YAspect;
  76.   WORD  PageWidth;
  77.   WORD  PageHeight;
  78. };
  79.  
  80. extern struct ExecBase  *SysBase;
  81. extern struct Library   *DOSBase;
  82. extern struct GfxBase   *GfxBase;
  83. extern struct Library   *CyberGfxBase;
  84. extern struct IntuitionBase *IntuitionBase;
  85. extern struct Library   *AslBase;
  86. extern struct Library   *GadToolsBase;
  87. extern struct Library   *UtilityBase;
  88.  
  89. #ifdef POWERUP
  90. extern struct Library   *PPCLibBase;
  91. #endif
  92.  
  93. verror_t VError;
  94.  
  95. void ASM RemapPixels(UBYTE * REG(a0), UBYTE * REG(a1), UBYTE *REG(a2), LONG REG(d0), LONG REG(d1), LONG REG(d2), LONG REG(d3));
  96. void ASM c2p(UBYTE * REG(a0), struct BitMap * REG(a1), WORD REG(d0), WORD REG(d1), WORD REG(d2), WORD REG(d3), LONG REG(d4));
  97.  
  98. #ifndef POWERUP
  99. static inline APTR memAlloc(ULONG size)
  100. {
  101.   return(AllocVec(size, MEMF_PUBLIC|MEMF_CLEAR));
  102. }
  103.  
  104. static inline void memFree(APTR mem)
  105. {
  106.   FreeVec(mem);
  107. }
  108. #else
  109. static inline APTR memAlloc(ULONG size)
  110. {
  111.   return(PPCAllocVec(size, MEMF_PUBLIC|MEMF_CLEAR));
  112. }
  113.  
  114. static inline void memFree(APTR mem)
  115. {
  116.   PPCFreeVec(mem);
  117. }
  118. #endif
  119.  
  120. ULONG ASM VBackFill(struct Hook *hook REG(a0), struct RastPort *rp REG(a2), struct BackFillMsg *bfm REG(a1))
  121. {
  122.   struct Layer  *l;
  123.   LONG          old_pen, new_pen;
  124.  
  125.   l         = rp->Layer;
  126.   rp->Layer = NULL;
  127.   old_pen   = GetAPen(rp);
  128.   new_pen   = ((struct Video *) hook->h_Data)->BackFillPen;
  129.  
  130.   if(new_pen != -1)
  131.     SetAPen(rp, new_pen);
  132.   else
  133.     SetAPen(rp, 0);
  134.  
  135.   RectFill(rp, bfm->Bounds.MinX, bfm->Bounds.MinY, bfm->Bounds.MaxX, bfm->Bounds.MaxY);
  136.  
  137.   SetAPen(rp, old_pen);
  138.  
  139.   rp->Layer = l;
  140.  
  141.   return(0);
  142. }
  143.  
  144. ULONG VGetBestMode(LONG width, LONG height, LONG depth)
  145. {
  146.   struct List          *mode_list;
  147.   struct CyberModeNode *mode_node;
  148.   ULONG                mode_id;
  149.   ULONG                fallback_id;
  150.   LONG                 mode_error;
  151.   LONG                 fallback_error;
  152.   LONG                 error;
  153.   
  154.   mode_id = INVALID_ID;
  155.  
  156.   if(CyberGfxBase)
  157.   {
  158.     mode_list = AllocCModeListTagList(NULL);
  159.     
  160.     if(mode_list)
  161.     {
  162.       mode_node = (struct CyberModeNode *) mode_list->lh_Head;
  163.       
  164.       mode_error     = 0xfffffff;
  165.       fallback_id    = INVALID_ID;
  166.       fallback_error = 0xfffffff;
  167.       
  168.       while(mode_node->Node.ln_Succ)
  169.       {
  170.         if(((depth <= 8) && (mode_node->Depth == 8))
  171.         || ((depth > 8) && (mode_node->Depth == depth)))
  172.         {
  173.           error = ABS(mode_node->Width - width) + ABS(mode_node->Height - height);
  174.  
  175.           if((mode_node->Width < width) || (mode_node->Height < height))
  176.           {
  177.             if(error < fallback_error)
  178.             {
  179.               fallback_id   = mode_node->DisplayID;
  180.               fallback_error  = error;
  181.             }
  182.           }
  183.           else
  184.           {
  185.             if(error < mode_error)
  186.             {
  187.               mode_id   = mode_node->DisplayID;
  188.               mode_error  = error;
  189.             }
  190.           }
  191.         }
  192.       
  193.         mode_node = (struct CyberModeNode *) mode_node->Node.ln_Succ;
  194.       }
  195.       
  196.       if(mode_id == INVALID_ID)
  197.         mode_id = fallback_id;
  198.  
  199.       FreeCModeList(mode_list);
  200.     }
  201.   }
  202.  
  203.   if((mode_id == INVALID_ID) && (depth <= 8))
  204.     mode_id = BestModeID(BIDTAG_Depth,         depth,
  205.                          BIDTAG_NominalWidth,  width,
  206.                          BIDTAG_NominalHeight, height,
  207.                          TAG_END);
  208.   
  209.   return(mode_id);
  210. }
  211.  
  212. struct Video *AllocVideo(Tag tags,...)
  213. {
  214.   struct Video               *video;
  215.   struct TagItem             *tag, *taglist;
  216.   struct ScreenModeRequester *screen_req;
  217.   struct Rectangle           rect;
  218.   struct Window              *win;
  219.  
  220.   STRPTR title;
  221.   LONG   i, w, h, depth, rb, gb, bb;
  222.   ULONG  max_colors;
  223.   ULONG  mode_id;
  224.   BOOL   use_screen, use_screen_req, no_refresh;
  225.  
  226.   if((video = AllocVec(sizeof(struct Video), MEMF_PUBLIC|MEMF_CLEAR)))
  227.   {
  228.     /* Setup defaults. */
  229.  
  230.     VError = None;
  231.  
  232.     mode_id        = INVALID_ID;
  233.     depth          = 0;
  234.     win            = NULL;
  235.     title          = NULL;
  236.     use_screen     = FALSE;
  237.     use_screen_req = FALSE;
  238.     no_refresh     = FALSE;
  239.     max_colors     = 256;
  240.  
  241.     video->Buffers = 1;
  242.  
  243.     video->VectorPen   = -1;
  244.     video->BackFillPen = -1;
  245.  
  246.     video->BackFillHook.h_Entry = (HOOKFUNC) VBackFill;
  247.     video->BackFillHook.h_Data  = (APTR) video;
  248.  
  249.     video->MaxFrameSkip = 4;
  250.  
  251.     taglist = (struct TagItem *) &tags;
  252.  
  253.     while((tag = NextTagItem(&taglist)))
  254.     {
  255.       switch(tag->ti_Tag)
  256.       {
  257.         case VA_UseScreen:
  258.           use_screen = tag->ti_Data;
  259.           break;
  260.  
  261.         case VA_UseScreenReq:
  262.           use_screen_req = tag->ti_Data;
  263.           break;
  264.  
  265.         case VA_Width:
  266.           video->Width = tag->ti_Data;
  267.           break;
  268.  
  269.         case VA_Height:
  270.           video->Height = tag->ti_Data;
  271.           break;
  272.  
  273.         case VA_Depth:
  274.           depth = tag->ti_Data;
  275.           break;
  276.  
  277.         case VA_ModeID:
  278.           mode_id = tag->ti_Data;
  279.           break;
  280.  
  281.         case VA_Buffers:
  282.           video->Buffers  = tag->ti_Data;
  283.  
  284.           if(video->Buffers > 3)
  285.             video->Buffers  = 3;
  286.           else if(!video->Buffers)
  287.             video->Buffers  = 1;
  288.           break;
  289.  
  290.         case VA_LessFlicker:
  291.           video->LessFlicker  = tag->ti_Data;
  292.           break;
  293.  
  294.         case VA_Title:
  295.           title = (STRPTR) tag->ti_Data;
  296.           break;
  297.  
  298.         case VA_Menu:
  299.           video->Menu = (struct Menu *) tag->ti_Data;
  300.           break;
  301.  
  302.         case VA_NoRefresh:
  303.           no_refresh  = tag->ti_Data;
  304.           break;
  305.  
  306.         case VA_FPS:
  307.           video->FPS = tag->ti_Data;
  308.           break;
  309.  
  310.         case VA_MaxColors:
  311.           max_colors = tag->ti_Data;
  312.           break;
  313.  
  314.         case VA_AutoFrameSkip:
  315.           video->AutoFrameSkip = tag->ti_Data;
  316.           break;
  317.  
  318.         case VA_MaxFrameSkip:
  319.           video->MaxFrameSkip = tag->ti_Data;
  320.           break;
  321.       }
  322.     }
  323.  
  324.     if(use_screen || use_screen_req)
  325.     {
  326.       if(ModeNotAvailable(mode_id))
  327.       {
  328.         mode_id = INVALID_ID;
  329.  
  330.         if(depth == 0)
  331.           for(; (depth < 32) && (1 << depth < max_colors); depth++);
  332.  
  333.         if(!use_screen_req)
  334.           mode_id = VGetBestMode(video->Width, video->Height, depth);
  335.  
  336.         if(mode_id == INVALID_ID)
  337.         {
  338.           screen_req = (struct ScreenModeRequester *) AllocAslRequest(ASL_ScreenModeRequest, NULL);
  339.  
  340.           if(screen_req)
  341.           {
  342.             if(AslRequestTags(screen_req, ASLSM_MinWidth,            video->Width,
  343.                                           ASLSM_MinHeight,           video->Height,
  344.                                           ASLSM_InitialDisplayDepth, depth,
  345.                                           ASLSM_DoDepth,             TRUE,
  346.                                           TAG_END))
  347.  
  348.             mode_id = screen_req->sm_DisplayID;
  349.             depth   = screen_req->sm_DisplayDepth;
  350.  
  351.             FreeAslRequest(screen_req);
  352.           }
  353.         }
  354.  
  355.       }
  356.  
  357.       if(mode_id != INVALID_ID)
  358.       {
  359.         if(QueryOverscan(mode_id, &rect, OSCAN_TEXT))
  360.         {
  361.           if(CyberGfxBase)
  362.             video->CyberMode = IsCyberModeID(mode_id);
  363.           else
  364.             video->CyberMode = FALSE;
  365.  
  366.           if(video->CyberMode && (depth < 8))
  367.             depth = 8;
  368.  
  369.           if(GfxBase->LibNode.lib_Version >= 40)
  370.             video->PixelMode = WriteChunkyPixels;
  371.           else
  372.             video->PixelMode = WritePixelArray;
  373.  
  374.           if(!video->CyberMode && (depth <= 8))
  375.             video->PixelMode = CustomC2P;
  376.  
  377.           if(video->Width < rect.MaxX - rect.MinX + 1)
  378.             w = rect.MaxX - rect.MinX + 1;
  379.           else
  380.             w = video->Width;
  381.  
  382.           if(video->Height < rect.MaxY - rect.MinY + 1)
  383.             h = rect.MaxY - rect.MinY + 1;
  384.           else
  385.             h = video->Height;
  386.  
  387.           if(video->PixelMode == CustomC2P)
  388.             w = ((w + 31) >> 5) << 5;
  389.  
  390.           if((1 << depth) < max_colors)
  391.           {
  392.             bb = depth / 3;
  393.             rb = (depth - bb) / 2;
  394.             gb = depth - rb - bb;
  395.  
  396.             video->Palette[0] = (1 << depth) << 16;
  397.  
  398.             for(i = 0; i < (1 << depth); i++)
  399.             {
  400.               video->Palette[3*i+1] = ((i / (1 << (gb + bb))) % (1 << rb)) << (32 - rb);
  401.               video->Palette[3*i+2] = ((i / (1 << bb)) % (1 << gb)) << (32 - gb);
  402.               video->Palette[3*i+3] = (i % (1 << bb)) << (32 - bb);
  403.             }
  404.             
  405.             video->Palette[3*i+1] = 0;
  406.           }
  407.  
  408.           video->Screen = OpenScreenTags(NULL, SA_DisplayID, mode_id,
  409.                                                SA_Width,     w,
  410.                                                SA_Height,    (video->CyberMode)
  411.                                                              ? h * video->Buffers
  412.                                                              : h,
  413.                                                SA_Depth,     depth,
  414.                                                SA_Colors32,  ((depth <= 8) && ((1 << depth) < max_colors))
  415.                                                              ? (ULONG) video->Palette
  416.                                                              : NULL,
  417.                                                SA_ShowTitle, FALSE,
  418.                                                SA_Overscan,  OSCAN_TEXT,
  419.                                                SA_Type,      CUSTOMSCREEN,
  420.                                                SA_Title,     (ULONG) title,
  421.                                                TAG_END);
  422.  
  423.           if(video->Screen)
  424.           {
  425.             if(!video->CyberMode && (video->Buffers > 1))
  426.             {
  427.               video->ScreenBuffers[0]   = AllocScreenBuffer(video->Screen, NULL, SB_SCREEN_BITMAP);
  428.               if(video->ScreenBuffers[0])
  429.               {
  430.                 video->ScreenBuffers[1]   = AllocScreenBuffer(video->Screen, NULL, 0);
  431.                 if(video->ScreenBuffers[1])
  432.                 {
  433.                   InitRastPort(&video->ScreenBufferRP);
  434.                   video->ScreenBufferRP.BitMap  = video->ScreenBuffers[1]->sb_BitMap;
  435.                   video->RastPort         = &video->ScreenBufferRP;
  436.  
  437.                   if(video->Buffers > 2)
  438.                   {
  439.                     video->ScreenBuffers[2]   = AllocScreenBuffer(video->Screen, NULL, 0);
  440.                       
  441.                     if(!video->ScreenBuffers[2])
  442.                       video->Buffers = 2; /* fall back to double buffering. */
  443.                   }
  444.  
  445.                   if(video->Buffers == 2)
  446.                   {
  447.                     video->ScreenBuffers[0]->sb_DBufInfo->dbi_UserData1                = (APTR) 1;
  448.                     video->ScreenBuffers[0]->sb_DBufInfo->dbi_SafeMessage.mn_ReplyPort = &video->ScreenBufferPort;
  449.                     video->ScreenBuffers[1]->sb_DBufInfo->dbi_UserData1                = (APTR) 0;
  450.                     video->ScreenBuffers[1]->sb_DBufInfo->dbi_SafeMessage.mn_ReplyPort = &video->ScreenBufferPort;
  451.                   }
  452.                 }
  453.                 else
  454.                   video->Buffers  = 1;
  455.               }
  456.               else
  457.                 video->Buffers  = 1;
  458.             }
  459.  
  460.             win = OpenWindowTags(NULL, WA_Width,         video->Screen->Width,
  461.                                        WA_Height,        video->Screen->Height,
  462.                                        WA_Left,          0,
  463.                                        WA_Top,           0,
  464.                                        WA_NoCareRefresh, no_refresh,
  465.                                        WA_SimpleRefresh, TRUE,
  466.                                        WA_Activate,      TRUE,
  467.                                        WA_Borderless,    TRUE,
  468.                                        WA_NewLookMenus,  TRUE,
  469.                                        WA_AutoAdjust,    FALSE,
  470.                                        WA_BackFill,      (ULONG) &video->BackFillHook,
  471.                                        WA_CustomScreen,  (ULONG) video->Screen,
  472.                                        WA_IDCMP,         video->Menu
  473.                                                          ? IDCMP_REFRESHWINDOW|IDCMP_MENUPICK
  474.                                                          : IDCMP_REFRESHWINDOW,
  475.                                        TAG_END);
  476.             
  477.             if(win)
  478.             {
  479.               video->ScreenBufferPort.mp_Node.ln_Type = NT_MSGPORT;
  480.               video->ScreenBufferPort.mp_Flags        = PA_SIGNAL;
  481.               video->ScreenBufferPort.mp_SigBit       = win->UserPort->mp_SigBit;           
  482.               video->ScreenBufferPort.mp_SigTask      = win->UserPort->mp_SigTask;            
  483.  
  484.               NewList(&video->ScreenBufferPort.mp_MsgList);
  485.  
  486.               video->Pointer  = AllocVec(8, MEMF_CHIP|MEMF_CLEAR);
  487.               
  488.               if(video->Pointer)
  489.                 SetPointer(win, video->Pointer, 0, 0, 0, 0);
  490.             }
  491.             else
  492.               VError = OpenWindowFailed;
  493.           }
  494.           else
  495.             VError = OpenScreenFailed;
  496.         }
  497.       }
  498.     }
  499.     else
  500.     {
  501.       win = OpenWindowTags(NULL, WA_InnerWidth,    video->Width,
  502.                                  WA_InnerHeight,   video->Height,
  503.                                  WA_DragBar,       TRUE,
  504.                                  WA_CloseGadget,   TRUE,
  505.                                  WA_DepthGadget,   TRUE,
  506.                                  WA_NoCareRefresh, no_refresh,
  507.                                  WA_SimpleRefresh, TRUE,
  508.                                  WA_Activate,      TRUE,
  509.                                  WA_NewLookMenus,  TRUE,
  510.                                  WA_AutoAdjust,    FALSE,
  511.                                  WA_BackFill,      (ULONG) &video->BackFillHook,
  512.                                  WA_Title,         (ULONG) title,
  513.                                  WA_IDCMP,         video->Menu
  514.                                                    ? IDCMP_REFRESHWINDOW|IDCMP_MENUPICK|IDCMP_CLOSEWINDOW
  515.                                                    : IDCMP_REFRESHWINDOW|IDCMP_CLOSEWINDOW,
  516.                                  TAG_END);
  517.  
  518.       if(win)
  519.       {
  520.         if(GfxBase->LibNode.lib_Version >= 40)
  521.           video->PixelMode = WriteChunkyPixels;
  522.         else
  523.           video->PixelMode = WritePixelArray;
  524.  
  525.         if(CyberGfxBase && win)
  526.           video->CyberMode = GetCyberMapAttr(win->RPort->BitMap, CYBRMATTR_ISCYBERGFX);
  527.         else
  528.           video->CyberMode = FALSE;
  529.       }
  530.       else
  531.         VError = OpenWindowFailed;
  532.     }
  533.  
  534.     if((video->Window = win))
  535.     {
  536.       w = video->Width;
  537.       h = video->Height;
  538.  
  539.       if((video->Buffers > 1) && video->Screen)
  540.         video->CurrentScreenBuffer    = 1;
  541.       else
  542.         video->CurrentScreenBuffer    = 0;
  543.  
  544.       video->Left   = (win->Width  + win->BorderLeft - win->BorderRight - w) >> 1;
  545.  
  546.       if((video->Buffers > 1) && video->Screen && video->CyberMode)
  547.       {
  548.         video->Top     = ((win->Height / video->Buffers) + win->BorderTop - win->BorderBottom - h) >> 1;
  549.         video->OffsetY = (win->Height / video->Buffers) * video->CurrentScreenBuffer;
  550.       }
  551.       else
  552.       {
  553.         video->Top     = (win->Height  + win->BorderTop - win->BorderBottom - h) >> 1;
  554.         video->OffsetY = 0;
  555.       }
  556.  
  557.       video->FrameBox[0].MinX = video->Left;
  558.       video->FrameBox[0].MinY = video->Top;
  559.       video->FrameBox[0].MaxX = video->Left + video->Width - 1;
  560.       video->FrameBox[0].MaxY = video->Top + video->Height - 1;
  561.  
  562.       video->FrameBox[1] = video->FrameBox[0];
  563.       video->FrameBox[2] = video->FrameBox[0];
  564.  
  565.       if(video->CyberMode)
  566.       {
  567.         video->PixelFormat = GetCyberMapAttr(win->RPort->BitMap, CYBRMATTR_PIXFMT);
  568.  
  569.         if(video->PixelFormat && (max_colors <= 256))
  570.         {
  571.           video->CGXHook = AllocCLUT8RemapHook(win->WScreen, NULL);
  572.  
  573.           if(video->CGXHook)
  574.           {
  575.             video->PixelMode = CGXHook;
  576.             video->VectorPen = ObtainPen(win->WScreen->ViewPort.ColorMap, -1, 0, 0, 0, PEN_EXCLUSIVE);
  577.  
  578.             CustomRemapCLUT8RemapHook(video->CGXHook, video->PackedPalette);
  579.           }
  580.         }
  581.         else
  582.           video->PixelMode = BltBitMapRastPort;
  583.       }
  584.  
  585.       if(video->Screen && ((1 << video->Screen->RastPort.BitMap->Depth) < max_colors))
  586.       {
  587.         video->RemapBuffer = AllocVec((((video->Width + 31) >> 5) << 5) * video->Height,
  588.                                       MEMF_PUBLIC|MEMF_CLEAR);
  589.       }
  590.  
  591.       if(video->PixelFormat)
  592.         video->BackFillPen = ObtainBestPenA(video->Window->WScreen->ViewPort.ColorMap, 0, 0, 0, NULL);
  593.       else
  594.         video->BackFillPen = -1;
  595.  
  596.       if(video->RastPort)
  597.       {
  598.         if(video->BackFillPen != -1)
  599.           SetAPen(video->RastPort, video->BackFillPen);
  600.         else
  601.           SetAPen(video->RastPort, 0);
  602.  
  603.         RectFill(video->RastPort,
  604.                  win->BorderLeft,                    win->BorderTop,
  605.                  win->Width - win->BorderRight - 1,  win->Height - win->BorderBottom - 1);
  606.       }
  607.       else
  608.         video->RastPort = win->RPort;
  609.  
  610.       EraseRect(win->RPort,
  611.                 win->BorderLeft,                   win->BorderTop,
  612.                 win->Width - win->BorderRight - 1, win->Height - win->BorderBottom - 1);
  613.  
  614.       if(GadToolsBase && video->Menu)
  615.       {
  616.         video->VisualInfo = GetVisualInfoA(win->WScreen, NULL);
  617.  
  618.         if(video->VisualInfo)
  619.         {
  620.           if(LayoutMenus(video->Menu, video->VisualInfo, GTMN_NewLookMenus, TRUE, TAG_END))
  621.             SetMenuStrip(win, video->Menu);
  622.         }
  623.       }
  624.  
  625.       video->TimerMsgPort.mp_Node.ln_Type = NT_MSGPORT;
  626.       video->TimerMsgPort.mp_Flags        = PA_SIGNAL;
  627.       video->TimerMsgPort.mp_SigBit       = video->Window->UserPort->mp_SigBit;
  628.       video->TimerMsgPort.mp_SigTask      = video->Window->UserPort->mp_SigTask;
  629.       NewList(&video->TimerMsgPort.mp_MsgList);
  630.       
  631.       video->TimerRequest = CreateIORequest(&video->TimerMsgPort, sizeof(struct timerequest));
  632.         
  633.       if(video->TimerRequest)
  634.       {
  635.         if(OpenDevice("timer.device", UNIT_MICROHZ, (struct IORequest *) video->TimerRequest, 0))
  636.         {
  637.           DeleteIORequest((struct IORequest *) video->TimerRequest);
  638.           video->TimerRequest = NULL;
  639.         }
  640.         else
  641.           video->TimerBase = (struct Library *) video->TimerRequest->tr_node.io_Device;
  642.       }
  643.  
  644.       if(video->PixelMode == WritePixelArray)
  645.       {
  646.         CopyMem(win->RPort, &video->TempRastPort, sizeof(struct RastPort));
  647.  
  648.         video->TempRastPort.Layer = NULL;
  649.  
  650.         video->TempRastPort.BitMap = AllocBitMap((((video->Width + 15) >> 4) << 4), 1, 8, 0, NULL);
  651.  
  652.         if(video->TempRastPort.BitMap)
  653.           return(video);
  654.           
  655.         VError = OutOfMemory;
  656.       }
  657.       else
  658.         return(video);
  659.     }
  660.   }
  661.   else
  662.     VError = OutOfMemory;
  663.  
  664.   FreeVideo(video);
  665.  
  666.   return(NULL);
  667. }
  668.  
  669. void FreeVideo(struct Video *video)
  670. {
  671.   if(video)
  672.   {
  673.     if(video->Window)
  674.     {
  675.       if(video->VisualInfo && video->Menu)
  676.         ClearMenuStrip(video->Window);
  677.  
  678.       if(video->VectorPen != -1)
  679.         ReleasePen(video->Window->WScreen->ViewPort.ColorMap, video->VectorPen);
  680.  
  681.       if(video->BackFillPen != -1)
  682.         ReleasePen(video->Window->WScreen->ViewPort.ColorMap, video->BackFillPen);
  683.  
  684.       CloseWindow(video->Window);
  685.  
  686.       if(video->PixelMode == WritePixelArray)
  687.       {
  688.         if(video->TempRastPort.BitMap)
  689.           FreeBitMap(video->TempRastPort.BitMap);
  690.       }
  691.  
  692.       if(video->CGXHook)
  693.         FreeCGXHook(video->CGXHook);
  694.  
  695.       if(video->RemapBuffer)
  696.         FreeVec(video->RemapBuffer);
  697.  
  698.       if(video->VectorBitMap)
  699.         FreeBitMap(video->VectorBitMap);
  700.  
  701.       if(video->VisualInfo)
  702.         FreeVisualInfo(video->VisualInfo);
  703.     }
  704.  
  705.     if(video->Screen)
  706.     {
  707.       if(video->BitMapLock)
  708.         UnLockBitMap(video->BitMapLock);
  709.     
  710.       if(video->ScreenBufferChange && (video->Buffers == 2))
  711.       {
  712.         WaitPort(&video->ScreenBufferPort);
  713.         GetMsg(&video->ScreenBufferPort);
  714.       }
  715.  
  716.       WaitBlit();
  717.  
  718.       if(video->ScreenBuffers[0])
  719.         FreeScreenBuffer(video->Screen, video->ScreenBuffers[0]);
  720.  
  721.       if(video->ScreenBuffers[1])
  722.         FreeScreenBuffer(video->Screen, video->ScreenBuffers[1]);
  723.  
  724.       if(video->ScreenBuffers[2])
  725.         FreeScreenBuffer(video->Screen, video->ScreenBuffers[2]);
  726.  
  727.       if(video->Pointer)
  728.         FreeVec(video->Pointer);
  729.  
  730.       CloseScreen(video->Screen);
  731.     }
  732.     
  733.     if(video->TimerRequest)
  734.     {
  735.       if(!CheckIO((struct IORequest *) video->TimerRequest))
  736.       {
  737.         AbortIO((struct IORequest *) video->TimerRequest);
  738.         WaitIO((struct IORequest *) video->TimerRequest);
  739.       }
  740.  
  741.       CloseDevice((struct IORequest *) video->TimerRequest);
  742.       DeleteIORequest((struct IORequest *) video->TimerRequest);
  743.     }
  744.  
  745.     FreeVec(video);
  746.   }
  747. }
  748.  
  749. void VBeginFrame(struct Video *video, LONG bgpen, UBYTE *palette)
  750. {
  751.   struct timeval time;
  752.  
  753.   ULONG *pal;
  754.   ULONG *cmap;
  755.   ULONG t;
  756.   LONG  i, j, k, l, depth, rb, gb, bb;
  757.   LONG  fps;
  758.  
  759.   if(video->TimerBase)
  760.   {
  761.     video->Frames[video->CurrentFrame].WaitTime.tv_secs  = 0;
  762.     video->Frames[video->CurrentFrame].WaitTime.tv_micro = 0;
  763.   
  764.     if(video->FPS && video->LimitSpeed && video->TimerRequest)
  765.     {
  766.       if(!CheckIO((struct IORequest *) video->TimerRequest))
  767.       {
  768.         GetSysTime(&time);
  769.         WaitIO((struct IORequest *) video->TimerRequest);
  770.         GetSysTime(&video->Frames[video->CurrentFrame].WaitTime);
  771.         SubTime(&video->Frames[video->CurrentFrame].WaitTime, &time);
  772.         AddTime(&video->TotalWaitTime, &video->Frames[video->CurrentFrame].WaitTime);
  773.       }
  774.     
  775.       video->TimerRequest->tr_node.io_Command = TR_ADDREQUEST;
  776.       video->TimerRequest->tr_time.tv_secs    = 0;
  777.       video->TimerRequest->tr_time.tv_micro   = (1 + video->FrameSkip) * 1000000 / video->FPS;
  778.       SendIO((struct IORequest *) video->TimerRequest);
  779.     }
  780.   }
  781.  
  782.   video->BackgroundPen  = bgpen;
  783.  
  784.   if((video->Buffers > 1) && video->Screen)
  785.   {
  786.     if(video->CyberMode)
  787.       video->OffsetY  = (video->Window->Height / video->Buffers) * video->CurrentScreenBuffer;
  788.                         
  789.     else if(video->ScreenBufferChange)
  790.     {
  791.       if(video->Buffers == 2)
  792.       {
  793.         WaitPort(&video->ScreenBufferPort);
  794.         video->CurrentScreenBuffer = *((ULONG *) (GetMsg(&video->ScreenBufferPort) + 1));
  795.       }
  796.       else
  797.         video->CurrentScreenBuffer = (video->CurrentScreenBuffer + 1) % video->Buffers;
  798.       
  799.       video->ScreenBufferRP.BitMap  = video->ScreenBuffers[video->CurrentScreenBuffer]->sb_BitMap;
  800.       video->ScreenBufferChange   = FALSE;
  801.     }
  802.   }
  803.  
  804.   cmap = video->CMAP;
  805.  
  806.   if(video->Screen && (!video->PixelFormat))
  807.   {
  808.     depth = video->Screen->RastPort.BitMap->Depth;
  809.  
  810.     if(!video->RemapBuffer)
  811.     {
  812.       pal = video->Palette;
  813.  
  814.       for(i = 0, k = 0; i < (1 << depth); i++)
  815.       {
  816.         if(palette[4*i])
  817.         {
  818.           palette[4*i]  = 0;
  819.  
  820.           j = i;
  821.           l = k;
  822.           k++;
  823.           do
  824.           {
  825.             cmap[i] = (palette[4*i+1] << 16) | (palette[4*i+2] << 8) | palette[4*i+3];
  826.  
  827.             pal[k++]  = palette[4*i+1] << 24;
  828.             pal[k++]  = palette[4*i+2] << 24;
  829.             pal[k++]  = palette[4*i+3] << 24;
  830.             i++;
  831.           } while((i < 256) && (palette[4*i]));
  832.  
  833.           pal[l]  = ((i - j) << 16) | j;
  834.         }
  835.       }
  836.  
  837.       if(k)
  838.       {
  839.         pal[k]  = 0;
  840.  
  841.         LoadRGB32(&video->Screen->ViewPort, pal);
  842.       }
  843.     }
  844.     else
  845.     {
  846.       pal = video->PackedPalette;
  847.  
  848.       for(i = 0; i < 256; i++)
  849.       {
  850.         if(palette[4*i])
  851.         {
  852.           palette[4*i]  = 0;
  853.  
  854.           cmap[i] = (palette[4*i+1] << 16) | (palette[4*i+2] << 8) | palette[4*i+3];
  855.  
  856.           bb = depth / 3;
  857.           rb = (depth - bb) / 2;
  858.           gb = depth - rb - bb;
  859.           
  860.           ((UBYTE *) pal)[i]  = ((palette[4*i+1] >> (8 - rb)) << (gb + bb))
  861.                     | ((palette[4*i+2] >> (8 - gb)) << (bb))
  862.                     | (palette[4*i+3] >> (8 - bb));
  863.         }
  864.       }
  865.     }
  866.   }
  867.   else if(video->CGXHook)
  868.   {
  869.     pal = video->PackedPalette;
  870.  
  871.     for(i = 0; i < 256; i++)
  872.     {
  873.       if(palette[4*i])
  874.       {
  875.         palette[4*i]  = 0;
  876.  
  877.         cmap[i] = (palette[4*i+1] << 16) | (palette[4*i+2] << 8) | palette[4*i+3];
  878.  
  879.         switch(video->PixelFormat)
  880.         {
  881.           case PIXFMT_RGB15:
  882.             ((UWORD *) pal)[i] = ((palette[4*i+1]&0xf8)<<7)|((palette[4*i+2]&0xf8)<<2)|(palette[4*i+3]>>3);
  883.             break;
  884.  
  885.           case PIXFMT_BGR15:
  886.             ((UWORD *) pal)[i] = ((palette[4*i+3]&0xf8)<<7)|((palette[4*i+2]&0xf8)<<2)|(palette[4*i+1]>>3);
  887.             break;
  888.  
  889.           case PIXFMT_RGB15PC:
  890.             ((UWORD *) pal)[i] = ((palette[4*i+1]&0xf8)>>1)|(palette[4*i+2]>>6)|((palette[4*i+2]&0x38)<<10)|((palette[4*i+3]&0xf8)<<5);
  891.             break;
  892.  
  893.           case PIXFMT_BGR15PC:
  894.             ((UWORD *) pal)[i] = ((palette[4*i+3]&0xf8)>>1)|(palette[4*i+2]>>6)|((palette[4*i+2]&0x38)<<10)|((palette[4*i+1]&0xf8)<<5);
  895.             break;
  896.  
  897.           case PIXFMT_RGB16:
  898.             ((UWORD *) pal)[i] = ((palette[4*i+1]&0xf8)<<8)|((palette[4*i+2]&0xfc)<<3)|(palette[4*i+3]>>3);
  899.             break;
  900.  
  901.           case PIXFMT_BGR16:
  902.             ((UWORD *) pal)[i] = ((palette[4*i+3]&0xf8)<<8)|((palette[4*i+2]&0xfc)<<3)|(palette[4*i+1]>>3);
  903.             break;
  904.  
  905.           case PIXFMT_RGB16PC:
  906.             ((UWORD *) pal)[i] = (palette[4*i+1]&0xf8)|(palette[4*i+2]>>5)|((palette[4*i+2]&0x1c)<<11)|((palette[4*i+3]&0xf8)<<5);
  907.             break;
  908.  
  909.           case PIXFMT_BGR16PC:
  910.             ((UWORD *) pal)[i] = (palette[4*i+3]&0xf8)|(palette[4*i+2]>>5)|((palette[4*i+2]&0x1c)<<11)|((palette[4*i+1]&0xf8)<<5);
  911.             break;
  912.  
  913.           case PIXFMT_BGR24:
  914.             ((ULONG *) pal)[i]  = (palette[4*i+3]<<16)|(palette[4*i+2]<<8)|palette[4*i+1];
  915.             break;
  916.  
  917.           case PIXFMT_RGB24:
  918.           case PIXFMT_ARGB32:
  919.             ((ULONG *) pal)[i]  = (palette[4*i+1]<<16)|(palette[4*i+2]<<8)|palette[4*i+3];
  920.             break;
  921.  
  922.           case PIXFMT_BGRA32:
  923.             ((ULONG *) pal)[i]  = (palette[4*i+3]<<24)|(palette[4*i+2]<<16)|(palette[4*i+1]<<8);
  924.             break;
  925.  
  926.           case PIXFMT_RGBA32:
  927.             ((ULONG *) pal)[i]  = (palette[4*i+1]<<24)|(palette[4*i+2]<<16)|(palette[4*i+3]<<8);
  928.             break;
  929.         }
  930.         
  931.         video->Palette[3*i+1] = palette[4*i+1];
  932.         video->Palette[3*i+2] = palette[4*i+2];
  933.         video->Palette[3*i+3] = palette[4*i+3];
  934.       }
  935.     }
  936.   }
  937.  
  938.   if(video->TimerBase)
  939.   {
  940.     /* Calculate fps. */
  941.  
  942.     GetSysTime(&time);
  943.     video->Frames[video->CurrentFrame].Time   = time;
  944.     video->Frames[video->CurrentFrame].Skipped  = video->FrameSkip + 1;
  945.     video->TotalFrames += video->Frames[video->CurrentFrame].Skipped;
  946.     video->CurrentFrame = (video->CurrentFrame + 1) % V_FrameHistory;
  947.     video->TotalFrames -= video->Frames[video->CurrentFrame].Skipped;
  948.     SubTime(&video->TotalWaitTime, &video->Frames[video->CurrentFrame].WaitTime);
  949.  
  950.     SubTime(&time, &video->Frames[video->CurrentFrame].Time);
  951.     t = ((time.tv_secs * 1000) + (time.tv_micro / 1000));
  952.     if(t)
  953.       video->CurrentFPS = (video->TotalFrames * 1000) / t;
  954.     else
  955.       video->CurrentFPS = 0;
  956.  
  957.     /* Auto frameskip. */
  958.  
  959.     if(video->AutoFrameSkip && video->FPS)
  960.     {
  961.       /* Calculate what the fps would be without speed limiting. */
  962.     
  963.       SubTime(&time, &video->TotalWaitTime);
  964.       t = ((time.tv_secs * 1000) + (time.tv_micro / 1000));
  965.       if(t)
  966.         fps = (video->TotalFrames * 1000) / t;
  967.       else
  968.         fps = 0;
  969.  
  970.       if((fps < (video->FPS - 5)) && (video->FrameSkip < video->MaxFrameSkip))
  971.         video->FrameSkip++;
  972.       else if((fps > (video->FPS + 5)) && (video->FrameSkip > 0))
  973.         video->FrameSkip--;
  974.     }
  975.   }
  976. }
  977.  
  978. void VEndFrame(struct Video *video)
  979. {
  980.   if((video->Buffers > 1) && video->Screen)
  981.   {
  982.     if(video->CyberMode)
  983.     {
  984.       video->Screen->ViewPort.RasInfo->RyOffset = (video->Window->Height / video->Buffers) * video->CurrentScreenBuffer;
  985.       ScrollVPort(&video->Screen->ViewPort);
  986.       video->CurrentScreenBuffer  = (video->CurrentScreenBuffer + 1) % video->Buffers;
  987.     }
  988.     else
  989.     {
  990.       video->ScreenBufferChange = ChangeScreenBuffer( video->Screen, 
  991.                                 video->ScreenBuffers[video->CurrentScreenBuffer]);
  992.     }
  993.   }
  994. }
  995.  
  996. struct VPixelArray *VAllocPixelArray(struct Video *video, LONG width, LONG height,
  997.                                      LONG dirty, ULONG *pixel_formats)
  998. {
  999.   struct VPixelArray *pa;
  1000.  
  1001.   ULONG pixel_format;
  1002.   ULONG depth;
  1003.   LONG  size;
  1004.   LONG  w, i;
  1005.  
  1006.   if(width && height)
  1007.   {
  1008.     switch(video->PixelMode)
  1009.     {
  1010.       case CustomC2P:
  1011.         w = ((width + 31) >> 5) << 5;
  1012.         break;
  1013.  
  1014.       case CGXHook:
  1015.       case BltBitMapRastPort:
  1016.       case WriteChunkyPixels:
  1017.         w = ((width + 3) >> 2) << 2;
  1018.         break;
  1019.  
  1020.       default:
  1021.         if(video->RemapBuffer)
  1022.           w = ((width + 3) >> 2) << 2;
  1023.         else
  1024.           w = ((width + 15) >> 4) << 4;
  1025.     }
  1026.   }
  1027.   else
  1028.     w = 0;
  1029.  
  1030.   size = sizeof(struct VPixelArray);
  1031.  
  1032.   if(video->PixelMode != BltBitMapRastPort)
  1033.     size += (w * height);
  1034.   
  1035.   if(dirty)
  1036.     size += height;
  1037.  
  1038.   pa  = memAlloc(size);
  1039.  
  1040.   if(pa)
  1041.   {
  1042.     pa->Video  = video;
  1043.     pa->Size   = size;
  1044.     pa->Width  = width;
  1045.     pa->Height = height;
  1046.     pa->StartX = 0;
  1047.     pa->StartY = 0;
  1048.     pa->EndX   = width - 1;
  1049.     pa->EndY   = height - 1;
  1050.  
  1051.     if(video->PixelMode == BltBitMapRastPort)
  1052.     {
  1053.       if(pixel_formats)
  1054.       {
  1055.         pixel_format = GetCyberMapAttr(video->Window->RPort->BitMap, CYBRMATTR_PIXFMT);
  1056.  
  1057.         /* Try to find the pixel format of the video window in the list
  1058.          * of possible pixel formats for this pixel array. */
  1059.       
  1060.         for(i = 0; pixel_formats[i] != ~0; i++)
  1061.         {
  1062.           if(pixel_formats[i] == pixel_format)
  1063.             break;
  1064.         }
  1065.         
  1066.         if(pixel_formats[i] == ~0)
  1067.         {
  1068.           /* Didn't find the exact pixel format so try to find one that will map
  1069.            * to the pixel format of the window. */
  1070.         
  1071.           if((pixel_format == PIXFMT_LUT8) || (pixel_formats[0] == ~0))
  1072.           {
  1073.             /* If the possible pixel formats list is empty or the pixel format
  1074.              * of the video window is palette based then fail. Any true color
  1075.              * pixel format can't be mapped to a palette based one. */
  1076.           
  1077.             memFree(pa);
  1078.             
  1079.             return(NULL);
  1080.           }
  1081.           
  1082.           pixel_format = pixel_formats[0];
  1083.         }
  1084.       }
  1085.       else
  1086.       {
  1087.         /* An empty possible pixel formats list defaults to only
  1088.          * a palette based pixel format. */
  1089.       
  1090.         pixel_format = PIXFMT_LUT8;
  1091.       }
  1092.     
  1093.       switch(pixel_format)
  1094.       {
  1095.         case PIXFMT_RGB15:
  1096.         case PIXFMT_BGR15:
  1097.         case PIXFMT_RGB15PC:
  1098.         case PIXFMT_BGR15PC:
  1099.           depth = 15;
  1100.           break;
  1101.  
  1102.  
  1103.         case PIXFMT_RGB16:
  1104.         case PIXFMT_BGR16:
  1105.         case PIXFMT_RGB16PC:
  1106.         case PIXFMT_BGR16PC:
  1107.           depth = 16;
  1108.           break;
  1109.  
  1110.         case PIXFMT_RGB24:
  1111.         case PIXFMT_BGR24:
  1112.           depth = 24;
  1113.           break;
  1114.  
  1115.         case PIXFMT_ARGB32:
  1116.         case PIXFMT_BGRA32:
  1117.         case PIXFMT_RGBA32:
  1118.           depth = 32;
  1119.           break;
  1120.  
  1121.         case PIXFMT_LUT8:
  1122.         default:
  1123.           depth = 8;
  1124.           break;
  1125.       }
  1126.       
  1127.       pa->BitMap = AllocBitMap(width, height, depth,
  1128.                                BMF_MINPLANES|BMF_CLEAR|BMF_SPECIALFMT|SHIFT_PIXFMT(pixel_format),
  1129.                                video->Window->RPort->BitMap);
  1130.  
  1131.       if(!pa->BitMap)
  1132.       {
  1133.         memFree(pa);
  1134.         
  1135.         return(NULL);
  1136.       }
  1137.  
  1138.       pa->BytesPerRow   = GetCyberMapAttr(pa->BitMap, CYBRMATTR_XMOD);
  1139.       pa->BytesPerPixel = GetCyberMapAttr(pa->BitMap, CYBRMATTR_BPPIX);
  1140.       pa->PixelFormat   = GetCyberMapAttr(pa->BitMap, CYBRMATTR_PIXFMT);
  1141.       pa->Pixels        = (UBYTE *) GetCyberMapAttr(pa->BitMap, CYBRMATTR_DISPADR);
  1142.       pa->PixelsSize    = pa->BytesPerRow * height;
  1143.  
  1144.       if(dirty)
  1145.         pa->DirtyLines = (UBYTE *) &pa[1];
  1146.     }
  1147.     else
  1148.     {
  1149.       pa->BitMap        = NULL;
  1150.       pa->BytesPerRow   = w;
  1151.       pa->BytesPerPixel = 1;
  1152.       pa->PixelFormat   = PIXFMT_LUT8;
  1153.       pa->Pixels        = (UBYTE *) &pa[1];
  1154.       pa->PixelsSize    = 0;
  1155.  
  1156.       if(dirty)
  1157.         pa->DirtyLines  = &pa->Pixels[w * height];
  1158.     }
  1159.  
  1160.     for(i = 0; i < 256; i++)
  1161.     {
  1162.       pa->Palette[i][0] = 1;
  1163.       pa->Palette[i][1] = 0;
  1164.       pa->Palette[i][2] = 0;
  1165.       pa->Palette[i][3] = 0;
  1166.     }
  1167.  
  1168. #ifdef POWERUP
  1169.     PPCCacheClearE(pa, pa->Size, CACRF_ClearD);
  1170. #endif
  1171.   }
  1172.  
  1173.   return(pa);
  1174. }
  1175.  
  1176. void VFreePixelArray(struct VPixelArray *pa)
  1177. {
  1178.   if(pa->BitMap)
  1179.     FreeBitMap(pa->BitMap);
  1180.  
  1181.   memFree(pa);
  1182. }
  1183.  
  1184. LONG _WritePixelArray(APTR a, UWORD b, UWORD c, UWORD d, struct RastPort *e, UWORD f, UWORD g, UWORD h, UWORD i, UBYTE j)
  1185. {
  1186.   LONG r;
  1187.   
  1188.   r = WritePixelArray(a,b,c,d,e,f,g,h,i,j);
  1189.  
  1190.   return(r);  
  1191. }
  1192.  
  1193. void VDrawPixelArray(struct VPixelArray *pa)
  1194. {
  1195.   struct Video  *video;
  1196.  
  1197.   UBYTE *pixels;
  1198.   UBYTE *remap_pixels;
  1199.   UBYTE *dirty_lines;
  1200.   ULONG bpr;
  1201.   ULONG remap_bpr;
  1202.   LONG  x, y, w, h;
  1203.   LONG  sy, iy;
  1204.  
  1205.   if(!pa->Width || !pa->Height)
  1206.     return;
  1207.  
  1208.   video = pa->Video;
  1209.   w   = pa->EndX - pa->StartX + 1;
  1210.   h   = pa->EndY - pa->StartY + 1;
  1211.   x   = video->Left + ((video->Width - w) >> 1);
  1212.   y   = video->Top + video->OffsetY + ((video->Height - h) >> 1);
  1213.  
  1214.   if(video->Screen)
  1215.     x &= 0xfffffffc;
  1216.  
  1217.   if(pa->DirtyLines)
  1218.   {
  1219.     dirty_lines = pa->DirtyLines + pa->StartY;
  1220.  
  1221.     switch(video->PixelMode)
  1222.     {
  1223.       case CustomC2P:
  1224.         x = x & 0xffffffe0;
  1225.         w = ((w + 31) >> 5) << 5;
  1226.         VSetFrameBox(video, x, y, x + w - 1, y + h - 1);
  1227.  
  1228.         pixels  = VGetPixelArrayAddr(pa);
  1229.         bpr   = pa->BytesPerRow;
  1230.  
  1231.         if(video->RemapBuffer)
  1232.         {
  1233.           remap_pixels  = video->RemapBuffer;
  1234.           remap_bpr   = ((video->Width + 31) >> 5) << 5;
  1235.           
  1236.           for(iy = 0; iy < h; iy++)
  1237.           {
  1238.             if(dirty_lines[iy])
  1239.             {
  1240.               dirty_lines[iy] = 0;
  1241.  
  1242.               sy = iy;
  1243.               iy++;
  1244.             
  1245.               while(dirty_lines[iy] && (iy < h))
  1246.                 dirty_lines[iy++] = 0;
  1247.  
  1248.               RemapPixels(pixels + (bpr * sy), remap_pixels, (UBYTE *) video->PackedPalette,
  1249.                     w, remap_bpr, iy - sy, bpr);
  1250.  
  1251.               c2p(remap_pixels, video->RastPort->BitMap,
  1252.                   w,            iy - sy,
  1253.                   x,            y + sy,
  1254.                   bpr);
  1255.             }
  1256.           }
  1257.         }
  1258.         else
  1259.         {
  1260.           for(iy = 0; iy < h; iy++)
  1261.           {
  1262.             if(dirty_lines[iy])
  1263.             {
  1264.               dirty_lines[iy] = 0;
  1265.  
  1266.               sy = iy;
  1267.               iy++;
  1268.             
  1269.               while(dirty_lines[iy] && (iy < h))
  1270.                 dirty_lines[iy++] = 0;
  1271.  
  1272.               c2p(pixels + (bpr * sy), video->RastPort->BitMap,
  1273.                   w,                   iy - sy,
  1274.                   x,                    y + sy,
  1275.                   bpr);
  1276.             }
  1277.           }
  1278.         }
  1279.         break;
  1280.  
  1281.       case BltBitMapRastPort:    
  1282.         VSetFrameBox(video, x, y, x + w - 1, y + h - 1);
  1283.         pixels = VGetPixelArrayAddr(pa);
  1284.         for(iy = 0; iy < h; iy++)
  1285.         {
  1286.           if(dirty_lines[iy])
  1287.           {
  1288.             dirty_lines[iy] = 0;
  1289.  
  1290.             sy = iy;
  1291.             iy++;
  1292.             
  1293.             while(dirty_lines[iy] && (iy < h))
  1294.               dirty_lines[iy++] = 0;
  1295.             
  1296.             BltBitMapRastPort(pa->BitMap, pa->StartX, pa->StartY + sy, video->RastPort,
  1297.                               x, y + sy, w, iy - sy, 0xc0);
  1298.           }
  1299.         }
  1300.         break;
  1301.  
  1302.       case WriteChunkyPixels:   
  1303.         VSetFrameBox(video, x, y, x + w - 1, y + h - 1);
  1304.         pixels = VGetPixelArrayAddr(pa);
  1305.         for(iy = 0; iy < h; iy++)
  1306.         {
  1307.           if(dirty_lines[iy])
  1308.           {
  1309.             dirty_lines[iy] = 0;
  1310.  
  1311.             sy = iy;
  1312.             iy++;
  1313.             
  1314.             while(dirty_lines[iy] && (iy < h))
  1315.               dirty_lines[iy] = 0;
  1316.             
  1317.             WriteChunkyPixels(  video->RastPort, x, y + sy, x + w - 1, y + iy - 1,
  1318.                       pixels + (pa->BytesPerRow * sy), pa->BytesPerRow);
  1319.           }
  1320.         }
  1321.         break;
  1322.  
  1323.       case CGXHook:
  1324.         VSetFrameBox(video, x, y, x + w - 1, y + h - 1);
  1325.         pixels = VGetPixelArrayAddr(pa);
  1326.         for(iy = 0; iy < h; iy++)
  1327.         {
  1328.           if(dirty_lines[iy])
  1329.           {
  1330.             dirty_lines[iy] = 0;
  1331.  
  1332.             sy = iy;
  1333.             iy++;
  1334.             
  1335.             while(dirty_lines[iy] && (iy < h))
  1336.               dirty_lines[iy] = 0;
  1337.             
  1338.             DoCLUT8RemapHook(video->CGXHook,
  1339.                              pixels + (pa->BytesPerRow * sy), video->RastPort,
  1340.                              0, 0, x, y + sy, w, iy - sy, pa->BytesPerRow);
  1341.           }
  1342.         }
  1343.         break;    
  1344.     }
  1345.   }
  1346.   else
  1347.   {
  1348.     switch(video->PixelMode)
  1349.     {
  1350.       case CustomC2P:
  1351.         x   = x & 0xffffffe0;
  1352.         w   = ((w + 31) >> 5) << 5;
  1353.         bpr   = pa->BytesPerRow;
  1354.         VSetFrameBox(video, x, y, x + w - 1, y + h - 1);
  1355.         pixels  = VGetPixelArrayAddr(pa);
  1356.         if(video->RemapBuffer)
  1357.         {
  1358.           bpr = ((video->Width + 31) >> 5) << 5;
  1359.           RemapPixels(pixels, video->RemapBuffer,  (UBYTE *) video->PackedPalette,
  1360.                 w, bpr, h, pa->BytesPerRow);
  1361.           pixels = video->RemapBuffer;
  1362.         }
  1363.  
  1364.         c2p( pixels, video->RastPort->BitMap,
  1365.             w,    h,
  1366.             x,    y,
  1367.             bpr);
  1368.         break;
  1369.  
  1370.       case BltBitMapRastPort:    
  1371.         VSetFrameBox(video, x, y, x + w - 1, y + h - 1);
  1372.         BltBitMapRastPort(pa->BitMap, pa->StartX, pa->StartY, video->RastPort,
  1373.                           x, y, w, h, 0xc0);
  1374.         break;
  1375.       case WriteChunkyPixels:   
  1376.         VSetFrameBox(video, x, y, x + w - 1, y + h - 1);
  1377.         WriteChunkyPixels(  video->RastPort, x, y, x + w - 1, y + h - 1,
  1378.                   VGetPixelArrayAddr(pa), pa->BytesPerRow);
  1379.         break;
  1380.       case CGXHook:
  1381.         VSetFrameBox(video, x, y, x + w - 1, y + h - 1);
  1382.         DoCLUT8RemapHook( video->CGXHook,
  1383.                   VGetPixelArrayAddr(pa), video->RastPort,
  1384.                   0,            0,
  1385.                   x,            y,
  1386.                   w,            h,
  1387.                   pa->BytesPerRow);
  1388.         break;    
  1389.     }
  1390.   }
  1391. }
  1392.  
  1393. void VSetPixelFrame(struct VPixelArray *pa)
  1394. {
  1395.   struct Video *video;
  1396.  
  1397.   video = pa->Video;
  1398.  
  1399.   VBeginFrame(video, pa->BackgroundPen, &pa->Palette[0][0]);
  1400.  
  1401.   video->CurrentPixelArray  = pa;
  1402.   video->CurrentVectorArray = NULL;
  1403.  
  1404.   VDrawPixelArray(pa);
  1405.  
  1406.   VEndFrame(video);
  1407. }
  1408.  
  1409. struct VVectorArray *VAllocVectorArray( struct Video *video, LONG width, LONG height, LONG length)
  1410. {
  1411.   struct VVectorArray *va;
  1412.  
  1413.   va  = memAlloc(sizeof(struct VVectorArray) + length * sizeof(struct VVector));
  1414.  
  1415.   if(va)
  1416.   {
  1417.     va->Video   = video;
  1418.     va->Size    = sizeof(struct VVectorArray) + length * sizeof(struct VVector);
  1419.     va->Width   = width;
  1420.     va->Height    = height;
  1421.     va->MaxLength = length;
  1422.     va->Vectors   = (struct VVector *) &va[1];
  1423.  
  1424. #ifdef POWERUP
  1425.     PPCCacheClearE(va, va->Size, CACRF_ClearD);
  1426. #endif
  1427.   }
  1428.  
  1429.   return(va);
  1430. }
  1431.  
  1432. void VFreeVectorArray(struct VVectorArray *va)
  1433. {
  1434.   memFree(va);
  1435. }
  1436.  
  1437. void VDrawVectorArray(struct VVectorArray *va)
  1438. {
  1439.   struct Video  *video;
  1440.   struct RastPort *rp;
  1441.   LONG      i, t, x1, y1, x2, y2, dx, dy, w, h, left, top, width, height;
  1442.  
  1443.   video = va->Video;
  1444.   rp    = NULL;
  1445.   left  = video->Left;
  1446.   top   = video->Top + video->OffsetY;
  1447.   width = video->Width;
  1448.   height  = video->Height;
  1449.   w   = va->Width;
  1450.   h   = va->Height;
  1451.  
  1452.   VSetFrameBox(video, left, top, left + w - 1, top + h - 1);
  1453.  
  1454.   if((video->Buffers > 1) && !video->Screen)
  1455.   {
  1456.     if(!video->VectorBitMap)
  1457.     {
  1458.       video->VectorBitMap = AllocBitMap(  width,  height, 
  1459.                         GetBitMapAttr(video->Window->RPort->BitMap, BMA_DEPTH),
  1460.                         BMF_MINPLANES,  video->Window->RPort->BitMap);
  1461.       if(video->VectorBitMap)
  1462.       {
  1463.         InitRastPort(&video->VectorRastPort);
  1464.         video->VectorRastPort.Layer   = NULL;
  1465.         video->VectorRastPort.BitMap  = video->VectorBitMap;
  1466.       }
  1467.     }
  1468.  
  1469.     if(video->VectorBitMap)
  1470.     {
  1471.       rp   = &video->VectorRastPort;
  1472.       left = 0;
  1473.       top  = 0;
  1474.     }
  1475.   }
  1476.   else
  1477.     rp    = video->RastPort;
  1478.  
  1479.   if(rp)
  1480.   {
  1481.     if(video->LessFlicker && !(video->Buffers > 1) && !video->VectorBitMap)
  1482.     {
  1483.       video->VectorBitMap = AllocBitMap(width, height, 1, 0, 0);
  1484.       if(video->VectorBitMap)
  1485.       {
  1486.         InitRastPort(&video->VectorRastPort);
  1487.         video->VectorRastPort.Layer   = NULL;
  1488.         video->VectorRastPort.BitMap  = video->VectorBitMap;
  1489.       }
  1490.     }
  1491.  
  1492.     if(!video->LessFlicker || !video->VectorBitMap)
  1493.     {
  1494.       if(video->CGXHook)
  1495.       {
  1496.         FillPixelArray( rp,
  1497.                 left,   top,
  1498.                 width,    height,
  1499.                 video->BackgroundColor);
  1500.       }
  1501.       else
  1502.       {
  1503.         SetAPen(rp, video->BackgroundPen);
  1504.  
  1505.         RectFill( rp,
  1506.               left,       top,
  1507.               left + width - 1, top + height - 1);
  1508.       }
  1509.     }
  1510.     else
  1511.     {
  1512.       SetAPen(&video->VectorRastPort, 1);
  1513.       RectFill(&video->VectorRastPort, 0, 0, width - 1, height - 1);
  1514.       SetAPen(&video->VectorRastPort, 0);
  1515.     }
  1516.  
  1517.     if(video->CGXHook)
  1518.       SetAPen(rp, video->VectorPen);
  1519.  
  1520.     x1  = video->VectorX;
  1521.     y1  = video->VectorY;
  1522.  
  1523.     for(i = 0; i < va->Length; i++)
  1524.     {
  1525.       if(va->Vectors[i].Pen >= 0)
  1526.       {
  1527.         x2  = va->Vectors[i].X;
  1528.         y2  = va->Vectors[i].Y;
  1529.  
  1530.         if(x1 > x2)
  1531.         {
  1532.           t = x2;
  1533.           x2  = x1;
  1534.           x1  = t;
  1535.           t = y2;
  1536.           y2  = y1;
  1537.           y1  = t;
  1538.         }
  1539.  
  1540.         if((x1 < w) && (x2 >= 0))
  1541.         {
  1542.           if(x1 != x2)
  1543.           {
  1544.             dy  = ((y2 - y1) << 16) / (x2 - x1);
  1545.  
  1546.             if(x1 < 0)
  1547.             {
  1548.               x1  = 0;
  1549.               y1  = y1 - ((x1 * dy) >> 16);
  1550.             }
  1551.  
  1552.             if(x2 >= w)
  1553.             {
  1554.               y2  = y2 - (((x2 - w - 1) * dy) >> 16);
  1555.               x2  = w - 1;
  1556.             }
  1557.           }
  1558.  
  1559.           if(y1 > y2)
  1560.           {
  1561.             t = x2;
  1562.             x2  = x1;
  1563.             x1  = t;
  1564.             t = y2;
  1565.             y2  = y1;
  1566.             y1  = t;
  1567.           }
  1568.           
  1569.           if((y1 < h) && (y2 >= 0))
  1570.           {
  1571.             if(y1 != y2)
  1572.             {
  1573.               dx  = ((x2 - x1) << 16) / (y2 - y1);
  1574.  
  1575.               if(y1 < 0)
  1576.               {
  1577.                 x1  = x1 - ((y1 * dx) >> 16);
  1578.                 y1  = 0;
  1579.               }
  1580.  
  1581.               if(y2 >= h)
  1582.               {
  1583.                 x2  = x2 - (((y2 - h - 1) * dx) >> 16);
  1584.                 y2  = h - 1;
  1585.               }
  1586.             }
  1587.  
  1588.             if(video->CGXHook)
  1589.             {
  1590.               SetRGB32( &video->Window->WScreen->ViewPort, video->VectorPen,
  1591.                     video->Palette[3*va->Vectors[i].Pen+1] << 24,
  1592.                     video->Palette[3*va->Vectors[i].Pen+2] << 24,
  1593.                     video->Palette[3*va->Vectors[i].Pen+3] << 24);
  1594.             }
  1595.             else
  1596.               SetAPen(rp, va->Vectors[i].Pen);
  1597.  
  1598.             Move(rp, left + x1, top + y1);
  1599.             Draw(rp, left + x2, top + y2);
  1600.  
  1601.             if(video->LessFlicker && video->VectorBitMap)
  1602.             {
  1603.               Move(&video->VectorRastPort, x1, y1);
  1604.               Draw(&video->VectorRastPort, x2, y2);
  1605.             }
  1606.           }
  1607.         }
  1608.       }
  1609.  
  1610.       x1 = va->Vectors[i].X;
  1611.       y1 = va->Vectors[i].Y;
  1612.     }
  1613.     
  1614.     video->VectorX  = x1;
  1615.     video->VectorY  = y1;
  1616.  
  1617.     if(video->VectorBitMap)
  1618.     {
  1619.       if(video->Buffers > 1)
  1620.         BltBitMapRastPort(  video->VectorBitMap,  0,        0,
  1621.                   video->RastPort,    video->Left,  video->Top + video->OffsetY,
  1622.                   width,          height,     0xc0);
  1623.       else
  1624.       {
  1625.         if(video->CGXHook)
  1626.         {
  1627.           SetRGB32( &video->Window->WScreen->ViewPort, video->VectorPen,
  1628.                 video->Palette[3*va->BackgroundPen+1] << 24,
  1629.                 video->Palette[3*va->BackgroundPen+2] << 24,
  1630.                 video->Palette[3*va->BackgroundPen+3] << 24);
  1631.         }
  1632.         else
  1633.           SetAPen(rp, va->BackgroundPen);
  1634.  
  1635.         SetDrMd(rp, JAM1);
  1636.  
  1637.         BltTemplate(video->VectorBitMap->Planes[0],   0, 
  1638.               video->VectorBitMap->BytesPerRow, rp, 
  1639.               video->Left,            video->Top + video->OffsetY,
  1640.               width,                height);
  1641.       }
  1642.     }
  1643.   }
  1644. }
  1645.  
  1646. void VSetVectorFrame(struct VVectorArray *va)
  1647. {
  1648.   struct Video  *video;
  1649.  
  1650.   video = va->Video;
  1651.  
  1652.   VBeginFrame(video, va->BackgroundPen, &va->Palette[0][0]);
  1653.  
  1654.   video->CurrentPixelArray  = NULL;
  1655.   video->CurrentVectorArray = va;
  1656.  
  1657.   VDrawVectorArray(va);
  1658.  
  1659.   VEndFrame(video);
  1660. }
  1661.  
  1662. struct VDirectArray *VAllocDirectArray(struct Video *video, LONG width, LONG height)
  1663. {
  1664.   struct VDirectArray *da;
  1665.   LONG        i;
  1666.  
  1667. #ifdef POWERUP  
  1668.   da = PPCAllocVec(sizeof(struct VDirectArray), MEMF_PUBLIC|MEMF_CLEAR|MEMF_NOCACHESYNCPPC|MEMF_NOCACHESYNCM68K);
  1669. #else
  1670.   da = AllocVec(sizeof(struct VDirectArray), MEMF_PUBLIC|MEMF_CLEAR);
  1671. #endif
  1672.  
  1673.   if(da)
  1674.   {
  1675.     da->Video = video;
  1676.     da->Width = width;
  1677.     da->Height  = height;
  1678.  
  1679.     for(i = 0; i < 256; i++)
  1680.     {
  1681.       da->Palette[i][0] = 1;
  1682.       da->Palette[i][1] = 0;
  1683.       da->Palette[i][2] = 0;
  1684.       da->Palette[i][3] = 0;
  1685.     }
  1686.   }
  1687.   
  1688.   return(da);
  1689. }
  1690.  
  1691. void VFreeDirectArray(struct VDirectArray *da)
  1692. {
  1693. #ifdef POWERUP
  1694.   PPCFreeVec(da);
  1695. #else
  1696.   FreeVec(da);
  1697. #endif
  1698. }
  1699.  
  1700. void VSetDirectFrame(struct VDirectArray *da)
  1701. {
  1702.   struct Video  *video;
  1703.   LONG      x;
  1704.   LONG      y;
  1705.  
  1706.   video = da->Video;
  1707.  
  1708.   if(video->CyberMode)
  1709.   {
  1710.     if(video->BitMapLock)
  1711.       UnLockBitMap(video->BitMapLock);
  1712.  
  1713.     VBeginFrame(video, da->BackgroundPen, &da->Palette[0][0]);
  1714.     VEndFrame(video);
  1715.  
  1716.     video->OffsetY = (video->Window->Height / video->Buffers) * video->CurrentScreenBuffer;
  1717.  
  1718.     x = (video->Left + ((video->Width - da->Width) >> 1)) & 0xfffffffc;;
  1719.     y = video->Top + video->OffsetY + ((video->Height - da->Height) >> 1);
  1720.  
  1721.     VSetFrameBox(video, x, y, x + da->Width - 1, y + da->Height - 1);
  1722.  
  1723.     video->CurrentPixelArray  = NULL;
  1724.     video->CurrentVectorArray = NULL;
  1725.  
  1726.     video->BitMapLock = LockBitMapTags(video->Screen->RastPort.BitMap,  LBMI_BASEADDRESS, (ULONG) &da->Pixels,
  1727.                                       LBMI_BYTESPERROW, (ULONG) &da->BytesPerRow,
  1728.                                       TAG_END);
  1729.     if(video->BitMapLock)
  1730.       da->Pixels += x + (da->BytesPerRow * y);
  1731.     else
  1732.     {
  1733.       da->Pixels    = NULL;
  1734.       da->BytesPerRow = 0;
  1735.     }
  1736.   }
  1737. }
  1738.  
  1739. void VSetFrameBox(struct Video *video, LONG sx, LONG sy, LONG ex, LONG ey)
  1740. {
  1741.   struct Rect32 *frame_box;
  1742.  
  1743.   frame_box = &video->FrameBox[video->CurrentScreenBuffer];
  1744.  
  1745.   if((sx > frame_box->MinX) || (sy > frame_box->MinY)
  1746.   || (ex < frame_box->MaxX) || (ey < frame_box->MaxY))
  1747.   {
  1748.     if(video->CGXHook)
  1749.     {
  1750.       FillPixelArray( video->RastPort,
  1751.               frame_box->MinX,
  1752.               frame_box->MinY,
  1753.               frame_box->MaxX - frame_box->MinX + 1,
  1754.               frame_box->MaxY - frame_box->MinY + 1,
  1755.               video->BackgroundColor);
  1756.     }
  1757.     else
  1758.     {
  1759.       SetAPen(video->RastPort, video->BackgroundPen);
  1760.  
  1761.       RectFill( video->RastPort,
  1762.             frame_box->MinX,  frame_box->MinY,
  1763.             frame_box->MaxX,  frame_box->MaxY);
  1764.     }
  1765.   }
  1766.  
  1767.   frame_box->MinX = sx;
  1768.   frame_box->MinY = sy;
  1769.   frame_box->MaxX = ex;
  1770.   frame_box->MaxY = ey;
  1771. }
  1772.  
  1773. void VRefresh(struct Video *video)
  1774. {
  1775.   if(video->CurrentPixelArray)
  1776.     VDrawPixelArray(video->CurrentPixelArray);
  1777.   else if(video->CurrentVectorArray)
  1778.     VDrawVectorArray(video->CurrentVectorArray);
  1779. }
  1780.  
  1781. void VSetFrameSkip(struct Video *video, LONG frameskip)
  1782. {
  1783.   video->FrameSkip = frameskip;
  1784. }
  1785.  
  1786. void VSetLimitSpeed(struct Video *video, LONG limitspeed)
  1787. {
  1788.   video->LimitSpeed = limitspeed;
  1789. }
  1790.  
  1791. LONG VSaveILBM(struct Video *video, STRPTR filename)
  1792. {
  1793.   BPTR  file;
  1794.   APTR  buffer;
  1795.   APTR  buf;
  1796.   UBYTE *pix;
  1797.   UBYTE *line;
  1798.   LONG  w;
  1799.   LONG  h;
  1800.   LONG  i;
  1801.   LONG  j;
  1802.   LONG  k;
  1803.   LONG  l;
  1804.   UWORD t;
  1805.  
  1806.   if(video->CurrentPixelArray)
  1807.   {
  1808.     w = video->CurrentPixelArray->EndX - video->CurrentPixelArray->StartX + 1;
  1809.     h = video->CurrentPixelArray->EndY - video->CurrentPixelArray->StartY + 1;
  1810.     
  1811.     buffer = AllocVec(9*sizeof(ULONG)+sizeof(struct BMHD)+(256*3)+(((w+15)&0xfffffff0)*h), MEMF_PUBLIC);
  1812.     
  1813.     buf = buffer;
  1814.     
  1815.     if(buf)
  1816.     {
  1817.       file = Open(filename, MODE_NEWFILE);
  1818.       
  1819.       if(file)
  1820.       {
  1821.         *((ULONG *) buf)++  = ID_FORM;
  1822.         *((ULONG *) buf)++  = 7*sizeof(ULONG)+sizeof(struct BMHD)+(256*3)+(((w+15)&0xfffffff0)*h);
  1823.         *((ULONG *) buf)++  = MAKE_ID('I','L','B','M');
  1824.         *((ULONG *) buf)++  = MAKE_ID('B','M','H','D');
  1825.         *((ULONG *) buf)++  = sizeof(struct BMHD);
  1826.         ((struct BMHD *) buf)->Width      = w;
  1827.         ((struct BMHD *) buf)->Height     = h;
  1828.         ((struct BMHD *) buf)->Left       = 0;
  1829.         ((struct BMHD *) buf)->Top        = 0;
  1830.         ((struct BMHD *) buf)->Planes     = 8;
  1831.         ((struct BMHD *) buf)->Masking      = 0;
  1832.         ((struct BMHD *) buf)->Compression    = 0;
  1833.         ((struct BMHD *) buf)->pad        = 0;
  1834.         ((struct BMHD *) buf)->TransparentColor = 0;
  1835.         ((struct BMHD *) buf)->XAspect      = 1;
  1836.         ((struct BMHD *) buf)->YAspect      = 1;
  1837.         ((struct BMHD *) buf)->PageWidth    = w;
  1838.         ((struct BMHD *) buf)->PageHeight   = h;
  1839.         ((struct BMHD *) buf)++;
  1840.         *((ULONG *) buf)++  = MAKE_ID('C','M','A','P');
  1841.         *((ULONG *) buf)++  = 256*3;
  1842.         for(i = 0; i < 256; i++)
  1843.         {
  1844.           *((UBYTE *) buf)++  = video->CMAP[i] >> 16;
  1845.           *((UBYTE *) buf)++  = (video->CMAP[i] >> 8) & 0xff;
  1846.           *((UBYTE *) buf)++  = video->CMAP[i] & 0xff;
  1847.         }
  1848.         *((ULONG *) buf)++  = MAKE_ID('B','O','D','Y');
  1849.         *((ULONG *) buf)++  = (((w+15)&0xfffffff0)*h);
  1850.         line = VGetPixelArrayAddr(video->CurrentPixelArray);
  1851.         for(i = 0; i < h; i++)
  1852.         {
  1853.           for(j = 0; j < 8; j++)
  1854.           {
  1855.             t = 0;
  1856.             l = 15;
  1857.             pix = line;
  1858.  
  1859.             for(k = 0; k < w; k++)
  1860.             {
  1861.               if(l > j)
  1862.                 t |= (*pix++ << (l - j)) & (1 << l);
  1863.               else
  1864.                 t |= (*pix++ >> (j - l)) & (1 << l);
  1865.               
  1866.               if(l)
  1867.                 l--;
  1868.               else
  1869.               {
  1870.                 *((UWORD *) buf)++ = t;
  1871.                 
  1872.                 t = 0;
  1873.                 l = 15;
  1874.               }
  1875.             }
  1876.             
  1877.             if(l < 15)
  1878.               *((UWORD *) buf)++ = t;
  1879.           }
  1880.           
  1881.           line += video->CurrentPixelArray->BytesPerRow;
  1882.         }
  1883.  
  1884.  
  1885.         Write(file, buffer, 9*sizeof(ULONG)+sizeof(struct BMHD)+(256*3)+(((w+15)&0xfffffff0)*h));
  1886.       
  1887.         Close(file);
  1888.       }
  1889.       
  1890.       FreeVec(buffer);
  1891.     }
  1892.   }
  1893.   
  1894.   return(0);
  1895. }
  1896.  
  1897. LONG VGetFrameSkip(struct Video *video)
  1898. {
  1899.   return(video->FrameSkip);
  1900. }
  1901.  
  1902. LONG VGetFPS(struct Video *video)
  1903. {
  1904.   return(video->CurrentFPS);
  1905. }
  1906.